package com.cnb.servlet.v2.web.servlet;

import com.cnb.servlet.util.StrUtil;
import com.cnb.servlet.v1.annotation.*;
import com.cnb.servlet.v2.context.ApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

public class CNBServlet extends HttpServlet {

    private Logger log = LoggerFactory.getLogger(CNBServlet.class);

    private Map<String,Method> pathMethod = new HashMap<String,Method>();

    private ApplicationContext ac;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Content-type", "text/html;charset=UTF-8");
        resp.setCharacterEncoding("UTF-8");
        try{
            doDispatch(req,resp);
        }catch (Exception e){
            resp.getWriter().write(e.getMessage());
        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws IOException, InvocationTargetException, IllegalAccessException {
        String requestURI = req.getRequestURI().replaceAll("/+","/");
        if(!this.pathMethod.containsKey(requestURI)){
            resp.getWriter().write("路径["+requestURI+"]没有找到!");
            return;
        }
        Method method = this.pathMethod.get(requestURI);


        Map<String,Integer> paramIndexMapping = new HashMap<String, Integer>();

        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            for (Annotation annotation : parameterAnnotations[i]) {
                if(annotation instanceof RequestParam){
                    String paramName = ((RequestParam) annotation).value();
                    if(!"".equals(paramName.trim())){
                        paramIndexMapping.put(paramName,i);
                    }
                }
            }
        }

        Class<?> [] paramTypes = method.getParameterTypes();
        for (int i = 0; i < paramTypes.length; i++) {
            Class<?> type = paramTypes[i];
            if(type == HttpServletRequest.class || type == HttpServletResponse.class){
                paramIndexMapping.put(type.getName(),i);
            }
        }

        Object[] paramValues = new Object[paramTypes.length];

        Map<String,String[]> params = req.getParameterMap();
        for (Map.Entry<String, String[]> param : params.entrySet()) {
            String value = Arrays.toString(param.getValue())
                    .replaceAll("\\[|\\]","")
                    .replaceAll("\\s","");

            if(!paramIndexMapping.containsKey(param.getKey())){continue;}

            int index = paramIndexMapping.get(param.getKey());

            //涉及到类型强制转换
            paramValues[index] = value;
        }

        if(paramIndexMapping.containsKey(HttpServletRequest.class.getName())){
            int index = paramIndexMapping.get(HttpServletRequest.class.getName());
            paramValues[index] = req;
        }

        if(paramIndexMapping.containsKey(HttpServletResponse.class.getName())){
            int index = paramIndexMapping.get(HttpServletResponse.class.getName());
            paramValues[index] = resp;
        }


        String beanName = StrUtil.toLowerCaseFirst(method.getDeclaringClass().getSimpleName());
        method.invoke(this.ac.getBean(beanName),paramValues);
    }

    @Override
    public void init(ServletConfig config) throws ServletException {

        ac = new ApplicationContext(config.getInitParameter("contextConfigLocation"));

        doInitHandlerMapping();

        log.info("框架初始化完成(*∩_∩*)~");
    }

    /**
     * 初始HandlerMapping MVC功能
     */
    private void doInitHandlerMapping() {
        if(this.ac.getBeanDefinitionCount() == 0){return;}
        for (String beanName : this.ac.getBeanDefinitionNames()) {
            Object beanClass = ac.getBean(beanName);
            Class<?> aClass = beanClass.getClass();

            //只有当该类上加入了Controller注解后才会初始化方法和接口名的对应
            if(!aClass.isAnnotationPresent(Controller.class)){
                continue;
            }

            String beasUrl = "";
            if(aClass.isAnnotationPresent(RequestMapping.class)){
                beasUrl = aClass.getAnnotation(RequestMapping.class).value();
            }

            Method[] publicMethods = aClass.getMethods();
            for (Method publicMethod : publicMethods) {
                if(!publicMethod.isAnnotationPresent(RequestMapping.class)){
                    continue;
                }
                RequestMapping requestMappingAnnotation = publicMethod.getAnnotation(RequestMapping.class);
                String url = requestMappingAnnotation.value();
                String allUrl =  ("/" + beasUrl + "/" + url).replaceAll("/+","/");
                pathMethod.put(allUrl,publicMethod);
            }
        }
    }
}
